/**
 * Copyright (c) 2022 Beijing Jiaotong University
 * PhotLab is licensed under [Open Source License].
 * You can use this software according to the terms and conditions of the [Open Source License].
 * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *
 * See the [Open Source License] for more details.
 *
 * Author: Zhenjie Wei
 * Created: Dec. 19, 2023
 * Supported by: National Key Research and Development Program of China
 */

// this function is to debounce a function
// there will be at most one call to the returned function in a delay
export function debounce<T extends (...args: any[]) => any>(
    fn: T,
    delay: number = 16
): T {
    let timer: ReturnType<typeof setTimeout>
    return ((...args: any[]) => {
        clearTimeout(timer)
        timer = setTimeout(() => {
            fn(...args)
        }, delay)
    }) as any
}

// decorator version of debounce
export function debounced(delay: number = 16) {
    return function (_t: any, _k: string, descriptor: PropertyDescriptor) {
        const original = descriptor.value
        descriptor.value = debounce(original, delay)
    }
}

// this function is to throttle a function
// once the returned function is called, other calls to the returned function within delay will be ignored
export function throttle<T extends (...args: any[]) => any>(
    fn: T,
    delay: number = 16
): T {
    let timer: ReturnType<typeof setTimeout> | undefined
    return ((...args: any[]) => {
        if (!timer) {
            timer = setTimeout(() => {
                fn(...args)
                timer = undefined
            }, delay)
        }
    }) as any
}

// decorator version of throttle
export function throttled(delay: number = 16) {
    return function (_t: any, _k: string, descriptor: PropertyDescriptor) {
        const original = descriptor.value
        descriptor.value = throttle(original, delay)
    }
}
